package com.lr.transfer.utils;

import com.lr.transfer.constant.ResultEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 压缩包下载
 * Created by yangyuanyuan on 2018/7/6.
 */
public class ZipUtil {
    private static Logger logger = LoggerFactory.getLogger(ZipUtil.class);

    /**
     * 将指定目录下源文件生成文件List
     *
     * @param baseDir
     * @param fileList
     */
    public static String getFileList(String baseDir, List<File> fileList) {
        File fileDir = new File(baseDir);//创建一个File对象
        if (!fileDir.exists() || !fileDir.isDirectory()) {  // 判断目录是否存在
            System.out.println("文件查找失败，待压缩文件目录：" + fileDir + "不存在！");
            logger.info("将指定目录下源文件生成文件List-文件目录不存在！！！");
            return ResultEnum.FAIL.getCode();
        }
        File tmpFile;
        File[] files = fileDir.listFiles();

        for (int i = 0; i < files.length; i++) {
            tmpFile = files[i];
            if (tmpFile.isFile()) {
                fileList.add(tmpFile);
            } else {
                getFileList(baseDir + tmpFile.getName() + File.separator, fileList);
            }
        }
        return ResultEnum.SUCCESS.getCode();
    }


    /**
     * 压缩文件，将listfiles源文件打包成zipname名称的zip文件，并存放在targetPath路径下
     *
     * @param filePath 待压缩文件路径
     * @param zipname  压缩后文件名称
     * @throws IOException
     */
    public static String createZip(HttpServletRequest request, HttpServletResponse response, String filePath, String zipname) {

        // OutputStream outputStream = null;
        ZipOutputStream zipOutputStream = null;
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                System.out.println("待压缩的文件不存在!");
                return ResultEnum.FAIL.getCode();
            }

//            File targetDir=new File(targetPath);//压缩后存放路径，目标路径创建一个File对象
//            if (!targetDir.exists()) {
//                targetDir.mkdirs();
//            }
            //outputStream = new BufferedOutputStream(new FileOutputStream(targetPath + "/"+zipname));
            //zipOutputStream = new ZipOutputStream(outputStream);

            response.reset();
            String UserAgent = request.getHeader("USER-AGENT").toLowerCase();
            if (UserAgent != null) {
                if (UserAgent.indexOf("firefox") > -1 || UserAgent.indexOf("chrome") > -1 || UserAgent.indexOf("safari") > -1) {
                    response.setHeader("Content-disposition", "attachment; filename=" + new String(zipname.getBytes("UTF-8"), "ISO-8859-1"));
                    response.setCharacterEncoding("ISO-8859-1");
                } else { // win10 ie edge 浏览器 和其他系统的ie
                    response.setHeader("Content-disposition", "attachment; filename=" + java.net.URLEncoder.encode(zipname, "utf-8"));
                    response.setCharacterEncoding("UTF-8");
                }
            } else {
                response.setHeader("Content-disposition", "attachment; filename=" + java.net.URLEncoder.encode(zipname, "utf-8"));
                response.setCharacterEncoding("utf-8");
            }
            response.setContentType("application/x-zip-compressed");
            zipOutputStream = new ZipOutputStream(response.getOutputStream());

            doCompress(file, zipOutputStream, "");

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != zipOutputStream) zipOutputStream.close();
                // if(null != outputStream) outputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return ResultEnum.SUCCESS.getCode();
    }

    /**
     * 压缩文件，将listfiles源文件打包成zipname名称的zip文件，并存放在targetPath路径下
     *
     * @param fileList 待压缩源文件
     * @param zipName   压缩后文件名称
     * @throws IOException
     */
    public static String writeZip(HttpServletRequest request, HttpServletResponse response, List<File> fileList, String zipName) {

        //OutputStream outputStream = null;
        ZipOutputStream zipOutputStream = null;
        try {
            if (null == fileList || fileList.size() == 0) {
                System.out.println("待压缩的文件：" + fileList + "不存在!");
                return ResultEnum.FAIL.getCode();
            }

//            File targetDir=new File(targetPath);//压缩后存放路径，创建一个File对象
//            if (!targetDir.exists()) {
//                targetDir.mkdirs();
//            }

            response.reset();
            String UserAgent = request.getHeader("USER-AGENT").toLowerCase();
            if (UserAgent != null) {
                if (UserAgent.indexOf("firefox") > -1 || UserAgent.indexOf("chrome") > -1 || UserAgent.indexOf("safari") > -1) {
                    response.setHeader("Content-disposition", "attachment; filename=" + new String(zipName.getBytes("UTF-8"), "ISO-8859-1"));
                    response.setCharacterEncoding("ISO-8859-1");
                } else { // win10 ie edge 浏览器 和其他系统的ie
                    response.setHeader("Content-disposition", "attachment; filename=" + java.net.URLEncoder.encode(zipName, "utf-8"));
                    response.setCharacterEncoding("UTF-8");
                }
            } else {
                response.setHeader("Content-disposition", "attachment; filename=" + java.net.URLEncoder.encode(zipName, "utf-8"));
                response.setCharacterEncoding("utf-8");
            }
            response.setContentType("application/x-zip-compressed");

            //outputStream = new BufferedOutputStream(new FileOutputStream(targetPath + "/"+zipname));

            //设置压缩流：直接写入response，实现边压缩边下载
            zipOutputStream = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
            zipOutputStream.setMethod(ZipOutputStream.DEFLATED); //设置压缩方法

            for (File file : fileList) {
                //压缩
                compress(file, zipOutputStream, "");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                //if(null != zipOutputStream) zipOutputStream.closeEntry();
                if (null != zipOutputStream) zipOutputStream.close();
                //if(null != outputStream) outputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return ResultEnum.SUCCESS.getCode();
    }

    /**
     * 复制sourceFilePath的文件到targetFile
     *
     * @param sourceFilePath
     * @param targetFile
     * @return
     */
    public static boolean copyFile(String sourceFilePath, String targetFile) {
        int endindex = sourceFilePath.lastIndexOf(File.separator);
        System.out.println("targetFile:" + targetFile);
        File targetDir = new File(targetFile);
        if (!targetDir.exists()) {
            targetDir.mkdirs();
            //targetDirFile.createNewFile();
        }
        File sourceFile = new File(sourceFilePath);
        System.out.println("sourceFile:" + sourceFile);
        if (!sourceFile.exists()) {
            logger.info("源文件不存在!" + sourceFilePath);
            return false;
        }
        File targetDirFile = new File(targetFile + sourceFilePath.substring(endindex));
        System.out.println("targetDirFile:" + targetDirFile);
        copy(sourceFile, targetDirFile);
        return true;

    }

    /**
     * 复制多级文件夹
     *
     * @param sourceFile 源文件
     * @param targetFile 目的文件
     * @return
     */
    public static void copyFolder(File sourceFile, File targetFile) {
        if (!targetFile.exists()) {
            targetFile.mkdir();
        }
        if (sourceFile.isDirectory()) {
            File newFolder = new File(targetFile, sourceFile.getName());
            newFolder.mkdirs();
            File[] files = sourceFile.listFiles();
            for (File file : files) {
                copyFolder(file, newFolder);
            }
        } else {
            File newFile = new File(targetFile, sourceFile.getName());
            copy(sourceFile, newFile);
        }
    }

    /**
     * 以流的形式下载文件
     */
    public static void downloadStream(HttpServletRequest request, HttpServletResponse response, String fileName, ZipOutputStream zipos) throws IOException {

        response.reset();
        String UserAgent = request.getHeader("USER-AGENT").toLowerCase();
        if (UserAgent != null) {
            if (UserAgent.indexOf("firefox") > -1 || UserAgent.indexOf("chrome") > -1 || UserAgent.indexOf("safari") > -1) {
                response.setHeader("Content-disposition", "attachment; filename=" + new String(fileName.getBytes("UTF-8"), "ISO-8859-1"));
                response.setCharacterEncoding("ISO-8859-1");
            } else { // win10 ie edge 浏览器 和其他系统的ie
                response.setHeader("Content-disposition", "attachment; filename=" + java.net.URLEncoder.encode(fileName, "utf-8"));
                response.setCharacterEncoding("UTF-8");
            }
        } else {
            response.setHeader("Content-disposition", "attachment; filename=" + java.net.URLEncoder.encode(fileName, "utf-8"));
            response.setCharacterEncoding("utf-8");
        }
        response.setContentType("application/x-zip-compressed");
        //设置压缩流：直接写入response，实现边压缩边下载
        zipos = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
        zipos.setMethod(ZipOutputStream.DEFLATED); //设置压缩方法
    }

    private static void copy(File oldfile, File newFile) {
        int length = 2097152;
        try {
            FileInputStream in = new FileInputStream(oldfile);
            FileOutputStream out = new FileOutputStream(newFile);
            byte[] buffer = new byte[length];
            int index = 0;
            while (true) {
                System.out.println("index:" + index++);
                int ins = in.read(buffer);
                System.out.println("ins" + ins);
                if (ins == -1) {
                    in.close();
                    out.flush();
                    out.close();
                    return;
                } else {
                    out.write(buffer, 0, ins);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 压缩目录
     *
     * @param dir
     * @param out
     * @param basedir
     */
    private static void compressDirectory(File dir, ZipOutputStream out, String basedir) {
        if (!dir.exists()) {
            dir.mkdir();
        }
        File[] files = dir.listFiles();
        for (int i = 0; i < files.length; i++) {
            //递归
            compress(files[i], out, basedir + dir.getName() + File.separator);
        }

    }

    /**
     * 压缩文件
     *
     * @param file
     * @param out
     * @param basedir
     */
    private static void compressFile(File file, ZipOutputStream out, String basedir) {
        if (!file.exists()) {
            return;
        }

        try {
            byte[] bytes = new byte[1024 * 5];// 读写缓冲区
            //压缩条目不是具体独立的文件，而是压缩包文件列表中的列表项，称为条目，就像索引一样
            ZipEntry zipEntry = new ZipEntry(file.getName());
            //定位到该压缩条目位置，开始写入文件到压缩包中
            out.putNextEntry(zipEntry);
            //读取待压缩的文件进压缩包
            BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
            int readLine = 0;
            while ((readLine = bufferedInputStream.read(bytes)) != -1) {
                out.write(bytes, 0, readLine);
            }
            bufferedInputStream.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 判断是目录还是文件，再进行相应的压缩
     * 所有文件跑到压缩包根目录下(注意：不保留目录结构可能会出现同名文件,会压缩失败)
     *
     * @param file
     * @param out
     * @param basedir
     */
    private static void compress(File file, ZipOutputStream out, String basedir) {
        if (file.isDirectory()) {
            //压缩一个目录
            compressDirectory(file, out, basedir);
        }        //压缩一个文件
        else if (file.isFile()) {
            compressFile(file, out, basedir);
        }
    }

    /**
     * 递归方法压缩
     * 保留目录结构
     *
     * @param srcFile 源文件
     * @param zos     输出流
     * @param zipName 压缩后的名称
     */
    private static void doCompress(File srcFile, ZipOutputStream zos, String zipName) {
        byte[] bytes = new byte[1024 * 5];// 读写缓冲区
        try {
            if (srcFile.isFile()) {
                zos.putNextEntry(new ZipEntry(zipName));
                int readLine = 0;
                FileInputStream in = new FileInputStream(srcFile);
                while ((readLine = in.read(bytes)) != -1) {
                    zos.write(bytes, 0, readLine);
                }
                zos.closeEntry();
                in.close();
            } else if (srcFile.isDirectory()) {
                File[] listFiles = srcFile.listFiles();
                if (listFiles == null || listFiles.length == 0) {
                    //zos.putNextEntry(new ZipEntry(zipName+File.separator));
                    zos.closeEntry();
                } else {
                    for (File file : listFiles) {
                        doCompress(file, zos, zipName + File.separator + file.getName());
                    }
                }

            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}
